////////////////////////////////////////////////////////////////////
// Programme d'utilisation de tables de Chrono Cross
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// Nemesis pour Terminus Traduction (tt_nemesis@yahoo.fr)
// Date de création :		24/08/03
// Dernière modification :	08/02/04
////////////////////////////////////////////////////////////////////

// Entete
#include "Table.h"

// Pointeur rencontré ou pas
int Tbl_Ptr;

// Types de données pour la table
// (Beuhhh j'occupe la mémoire)
typedef struct {
	char *code1;
	char *code2[TBL_ELMTS_NB];
	int type;
	int arg;
} Tbl_TElement;

// Table de caractères
static Tbl_TElement Tbl_table[TBL_ELMTS_NB];

/*------------------------------------------------------------------
  Chargement d'une table de caractères
--------------------------------------------------------------------
 <- nom = fichier table à ouvrir
 <- inout = TBL_IN ou TBL_OUT déterminant le dossier de la table
------------------------------------------------------------------*/
void Tbl_Charge(char *nom, int inout)
{
	// Fichier table
	FILE *table_f;
	char fichier[TBL_NOM_MAX];
	unsigned _int8 x1,x2;
	// Ligne du fichier table
	char ligne[TBL_LIGNE_MAX];
	// Caractéristique de l'élément
	int type;

	// Ouverture du fichier
	if (inout==TBL_IN)
		sprintf(fichier,"%s%s.%s",DIR_TABLES_IN,nom,EXT_TABLE);
	else
		sprintf(fichier,"%s%s.%s",DIR_TABLES_OUT,nom,EXT_TABLE);
	table_f=fopen(fichier, "rt");
	if (table_f!=NULL) {
		// Parcours de la table de caractères
		while(fgets(ligne,TBL_LIGNE_MAX,table_f)!=NULL) {
			// Test de commentaire
			if (ligne[0]!=COMMENT) {
				// Elimination du retour chariot
				ligne[strlen(ligne)-1]=0;
				// Récupération du premier code ASCII d'origine
				sscanf(&ligne[3],"%02x",&x1);
				// Enregistrement du type maximal et des paramètres
				type=ligne[0]-'0';
				// Mise à jour du type
				Tbl_table[x1].type=__max(Tbl_table[x1].type,type);
				// Remis chaque fois à jour (utile seulement une fois)
				if (Tbl_table[x1].arg==0)
					Tbl_table[x1].arg=ligne[1]-'0';
				// Récupération du second code ?
				if (Tbl_table[x1].type==2)
					sscanf(&ligne[5],"%02x",&x2);
				// Création de l'élément dans la table
				if (type==1) {
					// Cas particulier du saut de ligne
					if (ligne[6]==TBL_SPEC)
						Tbl_table[x1].code1=strdup(TBL_SAUT);
					else
						Tbl_table[x1].code1=strdup(&ligne[6]);
				} else
					Tbl_table[x1].code2[x2]=strdup(&ligne[8]);
			};
		};
		fclose(table_f);
	} else
		Main_Message_S("Impossible d'ouvrir la table\n","",ER);
}

/*------------------------------------------------------------------
  Libération mémoire de la table de caractères
------------------------------------------------------------------*/
void Tbl_Libere(void)
{
	// Indice dans la table
	int e1,e2;

	// Libération des chaînes de caractères
	for(e1=0;e1<TBL_ELMTS_NB;e1++) {
		// Cas de codes de type 2
		if (Tbl_table[e1].type==2) {
			for(e2=0;e2<TBL_ELMTS_NB;e2++)
				if (Tbl_table[e1].code2[e2]!=NULL) {
					free(Tbl_table[e1].code2[e2]);
					Tbl_table[e1].code2[e2]=NULL;
				};
		}
		if (Tbl_table[e1].code1!=NULL) {
			free(Tbl_table[e1].code1);
			Tbl_table[e1].code1=NULL;
		}
		Tbl_table[e1].type=0;
		Tbl_table[e1].arg=0;
	}
}

/*------------------------------------------------------------------
  Lecture d'un élément et éventuellement ses arguments
--------------------------------------------------------------------
 <- in_f = fichier dans lequel on lit les éléments
 <- out_f = fichier dans lequel on écrit le texte correspondant
 -> R_PTR si le caractère lu est un pointeur
	R_STD sinon
------------------------------------------------------------------*/
int Tbl_Lecture(FILE *in_f, FILE *out_f)
{
	// Caractères lus
	unsigned char c1,c2;
	// Position à conserver
	long pos=ftell(in_f)+1;
	// Chaine et arguments à écrire
	char chaine[TBL_CHAINE_MAX];
	int arg=0;
	int a;

	c1=fgetc(in_f);
	fseek(in_f,pos,SEEK_SET);
	switch (Tbl_table[c1].type) {
	// Cas d'un caractère inconnu
	case 0:
		sprintf(chaine,"%03d",c1);
		break;
	// Cas d'un caratère
	case 1:
		strcpy(chaine,Tbl_table[c1].code1);
		arg=Tbl_table[c1].arg;
		break;
	// Cas de 2 caractères
	case 2:
		c2=fgetc(in_f);
		if (Tbl_table[c1].code2[c2]==NULL) {
			if(Tbl_table[c1].code1==NULL) {
				sprintf(chaine,"%03d",c1);
				fseek(in_f,pos,SEEK_SET);
			} else {
				strcpy(chaine,Tbl_table[c1].code1);
				arg=Tbl_table[c1].arg;
				fseek(in_f,pos,SEEK_SET);
			}
		} else
			strcpy(chaine,Tbl_table[c1].code2[c2]);			
		break;
	default:
		Main_Message_S("Table invalide\n","",ER);
	}
	// Ecriture de la chaine en sortie
	if (strcmp(TBL_SAUT,chaine)==0)
		fprintf(out_f,chaine);
	else if (strlen(chaine)>1)
		fprintf(out_f,"%c%s%c",TBL_SPEC,chaine,TBL_SPEC);
	else
		fputc(chaine[0],out_f);
	// Lecture et écriture des paramètres
	for(a=0;a<arg;a++) {
		c2=fgetc(in_f);
		fprintf(out_f,"%c%03d%c",TBL_SPEC,c2,TBL_SPEC);		
	}

	// Test de pointeur ou saut
	if (strcmp(chaine,TBL_PTR)==0)
		return(R_PTR);
	else if (strcmp(chaine,TBL_SAUT)==0)
		return(R_SAUT);
	else
		return(R_STD);
}

/*------------------------------------------------------------------
  Ecriture d'un élément et éventuellement ses arguments
--------------------------------------------------------------------
 <- chaine = chaine recherchée
 <- out_f = fichier dans lequel on écrit les octets correspondants
 -> R_PTR si le caractère écrit est un pointeur
	R_STD sinon
------------------------------------------------------------------*/
int Tbl_Ecrit_Elem(char *chaine, FILE *out_f)
{
	// Caractères à écrire
	int c1=-1;
	int c2=-1;
	// Index de recherche
	int i1,i2;

	// Parcours de la table
	i1=0;
	while(c1<0 && i1<TBL_ELMTS_NB) {
		if (Tbl_table[i1].code1!=NULL
			&& strcmp(Tbl_table[i1].code1,chaine)==0) {
			c1=i1;
		} else if (Tbl_table[i1].type==2) {
			i2=0;
			while(c2<0 && i2<TBL_ELMTS_NB) {
				if (Tbl_table[i1].code2[i2]!=NULL
					&& strcmp(Tbl_table[i1].code2[i2],chaine)==0) {
					c1=i1;
					c2=i2;
				}
				// Changement du deuxième octet
				i2++;
			}
		}
		// Changement du premier octet
		i1++;
	}
	// Ecriture effective
	if (c1>=0) {
		fputc(c1,out_f);
		if (c2>=0)
			fputc(c2,out_f);
	} else {
		Main_Message_S("Element invalide \"%s\".\n",chaine,ER);
	}

	// Il s'agit d'un pointeur
	if (strcmp(chaine,TBL_PTR)==0)
		return(R_PTR);
	else
		return(R_STD);
}

/*------------------------------------------------------------------
  Traitement d'une ligne de texte à réinsérer
--------------------------------------------------------------------
 <- ligne = texte dans lequel on lit les éléments
 <- out_f = fichier dans lequel on écrit les octets correspondants
 -> R_PTR si le caractère écrit est un pointeur
	R_STD sinon
------------------------------------------------------------------*/
int Tbl_Ecriture(char *ligne, FILE *out_f)
{
	// Ecriture d'un pointeur ?
	int ptr=R_STD;
	// Position dans la chaîne
	unsigned int pos=0;
	// Longueur de la chaîne
	unsigned int l=strlen(ligne);
	// Adresse dans la chaîne de l'élément
	char *adresse1=ligne;
	char *adresse2;
	// Caractère à lire
	unsigned char c;
	// Chaine à rechercher
	char chaine[TBL_CHAINE_MAX];
	// Arguments
	char o;
	// Fin de ligne
	bool fin;

	// Cas d'une ligne vierge (-> fin de bloc)
	if (l==1 && (ligne[0]==10 || ligne[0]==13))
		ptr=R_FIN;
	else {
		// Parcours de la chaîne
		while(adresse1!=NULL) { // && ptr!=R_PTR
			// Traitement des lettres
			// Cas d'un code dès le départ
			adresse2=strtok_cc(adresse1,TBL_SPEC);
			if (adresse1!=NULL && adresse1[0]!=0) {
				c=0;
				fin = false;
				do {
					if (adresse1[c]!=10 && adresse1[c]!=13) {
						sprintf(chaine,"%c",adresse1[c]);
						Tbl_Ecrit_Elem(chaine,out_f); // ptr=
					} else {
						Tbl_Ecrit_Elem("\n",out_f); // ptr=
						fin = true;
					}
					c++;
				} while(c<strlen(adresse1) && !fin);
			}
			// Traitement des codes
			adresse1=strtok_cc(adresse2,TBL_SPEC);
			if (adresse2!=NULL && ptr!=R_FIN)
				if (sscanf(adresse2,"%03d",&o)>0) {
					fputc(o,out_f);
				} else
					ptr=Tbl_Ecrit_Elem(adresse2,out_f);
		};
	}
	return(ptr);
}
